﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MemoryFile.cs" company="">
//   
// </copyright>
// <summary>
//   The memory file.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Core
{
    using System;
    using System.IO;
    using System.Threading.Tasks;

    /// <summary>
    ///   The memory file.
    /// </summary>
    public class MemoryFile : IFile
    {
        #region Fields

        /// <summary>
        ///   The _bytes.
        /// </summary>
        private readonly byte[] _bytes;

        /// <summary>
        ///   The _description.
        /// </summary>
        private readonly FileDescription _description;

        /// <summary>
        ///   The _path.
        /// </summary>
        private string _path;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MemoryFile"/> class.
        /// </summary>
        /// <param name="name">
        /// The name. 
        /// </param>
        /// <param name="bytes">
        /// The bytes. 
        /// </param>
        public MemoryFile(string name, byte[] bytes)
        {
            this._bytes = bytes;
            var nameWithoutExtension = Path.GetFileName(name);
            var extension = PathUtility.GetExtensionWithoutDot(name);
            this._description = new FileDescription(nameWithoutExtension, extension, bytes.Length);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MemoryFile"/> class.
        /// </summary>
        /// <param name="name">
        /// The name. 
        /// </param>
        /// <param name="stream">
        /// The stream. 
        /// </param>
        public MemoryFile(string name, Stream stream)
            : this(name, stream.CopyToArray())
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MemoryFile"/> class.
        /// </summary>
        /// <param name="nameWithoutExtension">
        /// The name without extension. 
        /// </param>
        /// <param name="extension">
        /// The extension. 
        /// </param>
        /// <param name="bytes">
        /// The bytes. 
        /// </param>
        public MemoryFile(string nameWithoutExtension, string extension, byte[] bytes)
        {
            this._bytes = bytes;
            if (nameWithoutExtension == null)
            {
                nameWithoutExtension = Path.GetRandomFileName();
            }

            this._description = new FileDescription(nameWithoutExtension, extension, bytes.Length);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MemoryFile"/> class.
        /// </summary>
        /// <param name="nameWithoutExtension">
        /// The name without extension. 
        /// </param>
        /// <param name="extension">
        /// The extension. 
        /// </param>
        /// <param name="stream">
        /// The stream. 
        /// </param>
        public MemoryFile(string nameWithoutExtension, string extension, Stream stream)
            : this(nameWithoutExtension, extension, stream.CopyToArray())
        {
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        ///   The get description.
        /// </summary>
        /// <returns> The <see cref="FileDescription" /> . </returns>
        public FileDescription GetDescription()
        {
            return this._description;
        }

        /// <summary>
        ///   The get description async.
        /// </summary>
        /// <returns> The <see cref="Task" /> . </returns>
        public Task<FileDescription> GetDescriptionAsync()
        {
            // TODO Refactor to FromResult
            return Task.Factory.StartNew(() => this._description);
        }

        /// <summary>
        ///   The get path.
        /// </summary>
        /// <returns> The <see cref="string" /> . </returns>
        public string GetPath()
        {
            if (this._path == null)
            {
                var directoryPath = Path.GetTempPath();
                this._path = Path.Combine(directoryPath, this._description.Name);
                using (var fileStream = new FileStream(this._path, FileMode.CreateNew))
                {
                    fileStream.Write(this._bytes, 0, this._bytes.Length);
                }
            }

            return this._path;
        }

        /// <summary>
        ///   The get path async.
        /// </summary>
        /// <returns> The <see cref="Task" /> . </returns>
        public Task<string> GetPathAsync()
        {
            return Task.Factory.StartNew(() => this.GetPath());
        }

        /// <summary>
        ///   The get read stream.
        /// </summary>
        /// <returns> The <see cref="Stream" /> . </returns>
        public Stream GetReadStream()
        {
            return new MemoryStream(this._bytes);
        }

        /// <summary>
        ///   The get write stream.
        /// </summary>
        /// <returns> The <see cref="Stream" /> . </returns>
        /// <exception cref="NotImplementedException"></exception>
        public Stream GetWriteStream()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}